/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights
 * reserved. <a>http://www.cqcis.com</a>
 */
package com.cq.bd.service.impl;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import com.cq.bd.BDException;
import com.cq.bd.dao.SLoginLogDao;
import com.cq.bd.dao.SStaffDao;
import com.cq.bd.dao.SWorkerChgPwdDao;
import com.cq.bd.dao.SWorkerDao;
import com.cq.bd.dao.SWorkerOnlineDao;
import com.cq.bd.domain.SLoginLog;
import com.cq.bd.domain.SStaff;
import com.cq.bd.domain.SWorker;
import com.cq.bd.domain.SWorkerChgPwd;
import com.cq.bd.domain.SWorkerOnline;
import com.cq.bd.dto.ChgPwdResult;
import com.cq.bd.dto.LoginResult;
import com.cq.bd.security.UserDetails;
import com.cq.bd.service.LoginService;
import com.cq.bd.utils.AuthenticationHelper;
import com.cq.bd.utils.StringUtil;

/**
 * 登陆服务实现
 * 
 * @author huangmy
 * @date   2009-10-2
 */
public class LoginServiceImpl implements LoginService {
    private SWorkerDao sWorkerDao;
    private SStaffDao sStaffDao;
    private SLoginLogDao sLoginLogDao; // 员工登录错误日志表
    private SWorkerChgPwdDao sWorkerChgPwdDao; // 员工修改密码表
    private SWorkerOnlineDao sWorkerOnlineDao; // 员工在线记录表
    
    public void doLoginOut(UserDetails ud) {
        long loginLogId = ud.getLoginLogId();
        SLoginLog loginLog = this.sLoginLogDao.get(loginLogId);
        if (loginLog != null) {
            loginLog.setLogoutDate(new Date());            
            this.sLoginLogDao.update(loginLog);
        }
        
        SWorkerOnline workerOnline = this.sWorkerOnlineDao.get(ud.getOnLineId());
        if (workerOnline != null) {
            this.sWorkerOnlineDao.remove(workerOnline);
        }
    }
    
    public ChgPwdResult doChangePassword(long loginId, String oldPwd, String newPwd) {
        SWorker worker = this.sWorkerDao.get(loginId);
        if (worker == null) {
            ChgPwdResult result = new ChgPwdResult();
            result.setState(3);
            result.setMessage("用户不存在");
            return result;
        }
        
        String pwd = worker.getLoginPwd();
        if (!StringUtil.eq(pwd, oldPwd)) {
            // 密码错误
            ChgPwdResult result = new ChgPwdResult();
            result.setState(2);
            result.setMessage("密码错误，不能修改密码");
            return result;
        }
        
        worker.setLoginPwd(newPwd);
        worker.setLastChgPwdTime(new Date());
        this.sWorkerDao.update(worker);
        
        SWorkerChgPwd chgPwd = new SWorkerChgPwd();
        chgPwd.setAfterPwd(newPwd);
        chgPwd.setBeforePwd(oldPwd);
        chgPwd.setChgPwdTime(new Date());
        chgPwd.setLoginId(loginId);
        chgPwd.setSort(9);
        
        this.sWorkerChgPwdDao.create(chgPwd);
        
        ChgPwdResult result = new ChgPwdResult();
        result.setState(1);
        result.setMessage("修改密码成功!");
        return result;
    }
    
    /**
     * 登录日志
     * 
     * @param loginId
     * @param loginState
     * @return
     */
    private SLoginLog createLoginLog(Long loginId, Integer loginState) {
        SLoginLog loginLog = new SLoginLog();        
        loginLog.setIpAddr(AuthenticationHelper.getIpAddress());
        loginLog.setErrDesc(null);
        loginLog.setLoginId(loginId.intValue());
        loginLog.setLoginState(loginState);
        loginLog.setLoginTime(new Date());
        loginLog.setMacAddr(null);
        
        return loginLog;
    }
    
    /**
     * 登录错误记录
     * 
     * @param loginId
     * @return
     */
    @SuppressWarnings("unchecked")
    private List<SLoginLog> findErrorLoginLogs(Integer loginId) {
        return this.sLoginLogDao.find("from SLoginLog where loginId=? and loginState<>1", loginId);
    }
    
    /**
     * 某个时间点之后的登录错误记录
     * 
     * @param loginId
     * @param date
     * @return
     */
    @SuppressWarnings("unchecked")
    private List<SLoginLog> findDateErrorLoginLogs(Integer loginId, Date date) {
        return this.sLoginLogDao.find("from SLoginLog where loginId=? and loginState<>1 and loginTime>=?", loginId, date);
    }
    
    /**
     * 当天开始时间
     * 
     * @return
     */
    private static Date getTodayBegin() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.HOUR, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);            
        Date todayBegin = cal.getTime();
        
        return todayBegin;
    }
    
    public LoginResult doLogin(String loginCode, String password) {
        List<SWorker> workers = this.sWorkerDao.findBy("loginCode", loginCode);
        if (workers == null || workers.size() <= 0) { //  工号不存在
            return new LoginResult(LoginResult.STATE_LOGIN_FAILURE, 
                                   LoginResult.MESSGE_USER_NOT_EXIST);
        }
        
        SWorker worker = workers.get(0);
        // 查看工号是否被锁
        if (worker.getState() == 2) {
            // 已经被锁住，不允许登录
            return new LoginResult(LoginResult.STATE_LOGIN_FAILURE, 
                    "该用户名已经被锁定，请联系管理员！");
        } else if (worker.getState() != 1) {
            // 用户名无效
            return new LoginResult(LoginResult.STATE_LOGIN_FAILURE, 
                    "用户名无效，请检查用户名输入或者联系管理员！");
        }
        
        String pwd = worker.getLoginPwd();
        if (!StringUtil.eq(pwd, password)) {
            SLoginLog loginLog = createLoginLog(worker.getLoginId(), 0);
            loginLog.setErrDesc("密码错误");        
            this.sLoginLogDao.create(loginLog);
            

            
            List<SLoginLog> logins = findDateErrorLoginLogs(worker.getLoginId().intValue(), getTodayBegin());
            if (logins != null && logins.size() >= 3) { // 一天之内连续登录错误超过三次，将账号锁住
                worker.setState(2);
                this.sWorkerDao.update(worker);
            }
            
            return new LoginResult(LoginResult.STATE_LOGIN_FAILURE, 
                    "用户名或密码错误");
        }
                
        UserDetails ud = createUserDetail(worker);        
        AuthenticationHelper.setUser(ud);
        
        // 删除以前的错误登录日志
        List<SLoginLog> logins = findErrorLoginLogs(worker.getLoginId().intValue());
        if (logins != null) {
            for (SLoginLog l : logins) {
                this.sLoginLogDao.remove(l);
            }
        }
        
        // 写登录成功日志
        SLoginLog loginLog = createLoginLog(worker.getLoginId(), 1);
        loginLog.setErrDesc("登录成功");        
        Long loginLogId = (Long)this.sLoginLogDao.create(loginLog);
        ud.setLoginLogId(loginLogId);
        
        worker.setLoginNum(worker.getLoginNum() + 1);
        this.sWorkerDao.update(worker);
        
        // 登记员工在线
        SWorkerOnline workerOnline = new SWorkerOnline();
        workerOnline.setIpAddr(AuthenticationHelper.getIpAddress());
        workerOnline.setLoginDate(new Date());
        workerOnline.setLoginId(worker.getLoginId().intValue());
        workerOnline.setMacAddr(null);
        workerOnline.setMachineName(null);
        workerOnline.setNote(null);
        workerOnline.setSessionId(AuthenticationHelper.getSessionId());
        
        Long onlineId = (Long)this.sWorkerOnlineDao.create(workerOnline);
        
        ud.setOnLineId(onlineId);
        
        return new LoginResult(LoginResult.STATE_LOGIN_SUCCESS, 
                "登陆成功", ud);
    }
    
    /**
     * 生成用户详情
     * 
     * @param worker
     * @return
     */
    private UserDetails createUserDetail(SWorker worker) {
        UserDetails ud = new UserDetails();
        ud.setLoginId(worker.getLoginId());
        ud.setLoginCode(worker.getLoginCode());
        ud.setStaffId(worker.getStaffId());
        ud.setLoginPwd(worker.getLoginPwd());
        ud.setLoginType(worker.getLoginType());
        ud.setSendPhone(worker.getSendPhone());
        ud.setLoginNum(worker.getLoginNum());
        ud.setLastChgPwdTime(worker.getLastChgPwdTime());
        ud.setState(worker.getState());
        
        SStaff staff = this.sStaffDao.get(worker.getStaffId());
        if (staff == null) {
            throw new BDException("Can't find staff from staff_id: " + worker.getStaffId());
        }
        
        ud.setStaffName(staff.getStaffName());
        ud.setSex(staff.getSex());
        ud.setPlaceId(staff.getPlaceId());
        ud.setAge(staff.getAge());
        ud.setBirthday(staff.getBirthday());
        ud.setCardType(staff.getCardType());
        ud.setCardNo(staff.getCardNo());
        ud.setStaffType(staff.getStaffType());
        ud.setRelaPhone(staff.getRelaPhone());
        ud.setRelaMobile(staff.getRelaMobile());
        ud.setOtherRelaPhone(staff.getOtherRelaPhone());
        ud.setRelaAddr(staff.getRelaAddr());
        ud.setEmail(staff.getEmail());
        ud.setIpAddr(AuthenticationHelper.getIpAddress());
        ud.setSessionId(AuthenticationHelper.getSessionId());
        ud.setOnLineId(null);
        ud.setLoginLogId(null);
        
        return ud;
    }

    public void setSWorkerDao(SWorkerDao workerDao) {
        this.sWorkerDao = workerDao;
    }
    
    public void setSStaffDao(SStaffDao staffDao) {
        this.sStaffDao = staffDao;
    }

    public void setSLoginLogDao(SLoginLogDao loginLogDao) {
        sLoginLogDao = loginLogDao;
    }

    public void setSWorkerChgPwdDao(SWorkerChgPwdDao workerChgPwdDao) {
        sWorkerChgPwdDao = workerChgPwdDao;
    }

    public void setSWorkerOnlineDao(SWorkerOnlineDao workerOnlineDao) {
        sWorkerOnlineDao = workerOnlineDao;
    }
}
